package pl.com.ozzy.ozsign.digitalsign;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;

import pl.com.ozzy.ozsign.tools.AppConfigManager;
import android.os.Environment;

/**
 * This class contains methods to sign data with specified key read stored at
 * device.
 */
public class SignatureManager {

	/**
	 * Creates a pair of public and private keys using DSA algorithm
	 * 
	 * @throws NoSuchProviderException
	 * @throws NoSuchAlgorithmException
	 * @throws IOException
	 */
	public void createKeyPair(String privKeyName, String pubKeyName)
			throws NoSuchAlgorithmException, NoSuchProviderException,
			IOException {
		KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
		SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
		keyGen.initialize(1024, random);
		KeyPair pair = keyGen.generateKeyPair();
		PrivateKey priv = pair.getPrivate();
		PublicKey pub = pair.getPublic();

		/*
		 * Store key pair in external phone memory
		 */
		storeKeyPair(priv, privKeyName, pub, pubKeyName);
	}

	/**
	 * Signs the data specified by resource name
	 * 
	 * @throws NoSuchProviderException
	 * @throws NoSuchAlgorithmException
	 * @throws InvalidKeyException
	 * @throws IOException
	 * @throws SignatureException
	 */
	public void signData(PrivateKey key, String filePath) throws NoSuchAlgorithmException,
			NoSuchProviderException, InvalidKeyException, SignatureException,
			IOException {
		Signature dsa = Signature.getInstance("SHA1withDSA");
		dsa.initSign(key);

		FileInputStream fis = new FileInputStream(Environment
				.getExternalStorageDirectory().getAbsolutePath().concat(filePath));
		BufferedInputStream bufin = new BufferedInputStream(fis);
		byte[] buffer = new byte[1024];
		int len;
		while ((len = bufin.read(buffer)) >= 0) {
			dsa.update(buffer, 0, len);
		}
		;
		bufin.close();

		byte[] realSig = dsa.sign();
		FileOutputStream fos = new FileOutputStream(Environment
				.getExternalStorageDirectory().getAbsolutePath());
		fos.write(realSig);
		fos.close();
	}

	/**
	 * Stores key pair in internal storage
	 * 
	 * @throws FileNotFoundException
	 */
	private void storeKeyPair(PrivateKey priv, String privKeyName,
			PublicKey pub, String pubKeyName) throws FileNotFoundException,
			IOException {
		/* Save the signature in a file */
		byte[] privKey = priv.getEncoded();
		FileOutputStream sigfos = new FileOutputStream(
				AppConfigManager.mKeyStorePath.concat("/").concat(privKeyName));
		sigfos.write(privKey);
		sigfos.close();

		/* Save the public key in a file */
		byte[] pubKey = pub.getEncoded();
		FileOutputStream keyfos = new FileOutputStream(
				AppConfigManager.mKeyStorePath.concat("/").concat(pubKeyName));
		keyfos.write(pubKey);
		keyfos.close();
	}
}
